/*
 * SemanticAnalisys.cpp
 *
 *  Created on: 18/05/2010
 *      Author: rodolfo
 */

#include "SemanticAnalisys.h"

SemanticAnalisys::SemanticAnalisys() {
    symbolTable.clear();
}

void SemanticAnalisys::error( std::string string ) {
	std::cout << string << std::endl;
}

SemanticAnalisys::~SemanticAnalisys() {
	if( !symbolTable.empty() )
		symbolTable.clear();
	if ( identPair != 0 )
		delete identPair;
}

SemanticAnalisys::SemanticAnalisys( CompoundStatement *program ) {
    symbolTable.clear();
    if ( program != NULL ) {
        appendSymbolTable( program->declarationList );
        Statements::iterator statementsIt = program->statementList->begin();
        while ( statementsIt != program->statementList->end() )
        {
			statementAnalisys ( ( *statementsIt ) );
			statementsIt++;
        }
    }
}

void SemanticAnalisys::statementAnalisys( Statement *statement ) {
    switch ( statement->kind ) {
        case Statement::compoundStm:
            compoundStatementAnalisys( reinterpret_cast<CompoundStatement*> ( statement ) );
            break;
        case Statement::doStm:
            doStatementAnalisys( reinterpret_cast<Do*> ( statement ) );
            break;
        case Statement::elseStm:
            elseStatementAnalisys( reinterpret_cast<Else*> ( statement ) );
            break;
        case Statement::expStm:
            expressionStatementAnalisys( reinterpret_cast<ExpressionStatement*> ( statement ) );
            break;
        case Statement::forStm:
            forStatementAnalisys( reinterpret_cast<For*> ( statement ) );
            break;
        case Statement::ifStm:
            ifStatementAnalisys( reinterpret_cast<If*> ( statement ) );
            break;
        case Statement::whileStm:
            whileStatementAnalisys( reinterpret_cast<While*> ( statement ) );
            break;
    }

}
const std::string& SemanticAnalisys::expressionAnalisys( Expression *expression ) {
    switch ( expression->kind ) {
        case Expression::unExp: {
            unaryExpressionAnalisys( reinterpret_cast<UnaryExpression*> ( expression ) );
			return "";
            break;
        }
        case Expression::binExp: {
            binaryExpressionAnalisys( reinterpret_cast<BinaryExpression*> ( expression ) );
			return "";
            break;
        }
        case Expression::constantExp: {
            return expression->value;
            break;
        }
        case Expression::identifierExp: {
            identifierAnalisys( reinterpret_cast<Identifier*> ( expression ) );
			return "";
            break;
        }
        case Expression::strExp: {
            return expression->value;
            break;
        }
        case Expression::decExp: {
            declarationAnalisys( reinterpret_cast<Declaration*> ( expression ) );
			return "";
        }
        default:
            return "";
    }
}

void SemanticAnalisys::assigmentAnalyse( BinaryExpression *binaryExpression ) {
    if ( binaryExpression->lhs->kind != Expression::identifierExp )
        error( "Identifier required as left operand of assignment" );
    else {
        Identifier *idl = reinterpret_cast<Identifier*> ( binaryExpression->lhs );

		if ( !find( (*idl->name) ) ) {
			error( "Identifier: \"" +*idl->name+ "\" not declared! " );
		}

        switch ( binaryExpression->rhs->kind ) {
            case Expression::identifierExp: {
                Identifier *idr = reinterpret_cast<Identifier*> ( binaryExpression->rhs );
 
				if ( !find( (*idr->name) ) ) {
					error( "Identifier: \"" +*idr->name+ "\" not declared! " );
				}
				break;
            }
            case Expression::binExp: {
                binaryExpressionAnalisys( reinterpret_cast<BinaryExpression*> ( binaryExpression->rhs ) );
                break;
            }
            default: {
                expressionAnalisys( binaryExpression->rhs );
                break;
            }

        }
    }
}

void SemanticAnalisys::binaryExpressionAnalisys( BinaryExpression *binaryExpression ) {

    switch ( binaryExpression->op ) {
        case DIVOP: {
            expressionAnalisys( binaryExpression->lhs );
            if ( binaryExpression->rhs->kind == Expression::constantExp && binaryExpression->rhs->value == "0" ) {
                error( "Invalid division by zero!" );
            } else {
				expressionAnalisys( binaryExpression->rhs );
			}
            break;
        }
        case REMOP: {
            if ( binaryExpression->lhs->kind != binaryExpression->rhs->kind ) 
				error( "invalid operands to binary %" );
            expressionAnalisys( binaryExpression->lhs );
            if ( binaryExpression->rhs->kind == Expression::constantExp && binaryExpression->rhs->value == "0" ) {
                error( "Invalid division by zero!" );
            } else {
				expressionAnalisys( binaryExpression->rhs );
			}
            break;
        }
		case MULTOP:
		case MINOP:
		case PLUSOP:
        case GTOP:
        case LEOP:
        case GEOP:
        case EQOP:
        case NEOP:
        case LTOP:
        case ANDOP:
        case OROP: {
            expressionAnalisys( binaryExpression->rhs );
            expressionAnalisys( binaryExpression->lhs );
            break;
        }

        case SIASSIG:
        case DIASSIG:
        case REASSIG:
        case PLASSIG:
        case MIASSIG:
        case MUASSIG: {
            assigmentAnalyse( binaryExpression );
            break;
        }

    }
}

void SemanticAnalisys::forStatementAnalisys( For *forStatement ) {
	if ( forStatement->declaration != 0 )
	    expressionStatementAnalisys( forStatement->declaration );
	if ( forStatement->condition != 0 )
	    expressionStatementAnalisys( forStatement->condition );
	if ( forStatement->inc != 0 )
	    expressionAnalisys( forStatement->inc );
	if ( forStatement->command != 0 )
	    statementAnalisys( forStatement->command );
}


void SemanticAnalisys::unaryExpressionAnalisys( UnaryExpression *unaryExpression ) {
    if ( unaryExpression->expression->kind != Expression::identifierExp ) {
        if ( unaryExpression->op == PLUSPLUS ) 
			error( "Identifier required as increment operand" );
        if ( unaryExpression->op == MINUSMINUS ) 
			error( "Identifier required as decrement operand" );
    }
}

void SemanticAnalisys::ifStatementAnalisys( If *ifStatement ) {
    expressionAnalisys( ifStatement->condition );
    statementAnalisys( ifStatement->command );
    if ( ifStatement->elseStatement != 0 ) 
		statementAnalisys( ifStatement->elseStatement );
}

void SemanticAnalisys::declarationAnalisys( Declaration *declaration ) {
    std::vector<Identifier*>::iterator it = declaration->identifierList->begin();
    while ( it != declaration->identifierList->end() ) {
        ( *it )->type = declaration->type;
        it++;
    }
}

void SemanticAnalisys::whileStatementAnalisys( While *whileStatement ) {
    expressionAnalisys( whileStatement->condition );
    statementAnalisys( whileStatement->command );
}

void SemanticAnalisys::elseStatementAnalisys( Else *elseStatement ) {
    statementAnalisys( elseStatement->command );
}

void SemanticAnalisys::doStatementAnalisys( Do *doStatement ) {
    expressionAnalisys( doStatement->condition );
    statementAnalisys( doStatement->command );
}

void SemanticAnalisys::compoundStatementAnalisys( CompoundStatement *compoundStatement ) {
//    appendSymbolTable( compoundStatement->declarationList );
    Statements::iterator it = compoundStatement->statementList->begin();
    while ( it != compoundStatement->statementList->end() ) {
        statementAnalisys( ( *it ) );
		it++;
    }
}

void SemanticAnalisys::identifierAnalisys( Identifier *identifier ) {
	if ( !find( *identifier->name ) ) 
        error( "Identifier " + *identifier->name + " not declared" );
}

std::string SemanticAnalisys::expressionStatementAnalisys( ExpressionStatement *expressionStatement ) {
    return expressionAnalisys( expressionStatement->exp );
}
bool SemanticAnalisys::find( std::string& str ) {
    return ( ( symbolTable.find( str ) ) != symbolTable.end() );
}
void SemanticAnalisys::appendSymbolTable( Declarations *declarationList ) {
    if ( declarationList != 0 ) {
        Declarations::iterator it = declarationList->begin();
        while ( it != declarationList->end() ) {
            declarationAnalisys( ( *it ) );
			if ( (*it)->identifierList != 0 ) {
	            std::vector<Identifier*>::iterator identifiers = (*it)->identifierList->begin();
	            while ( identifiers != (*it)->identifierList->end() ) {
					if ( (*identifiers)->name != 0 ) {
	                    if ( !find( *( (*identifiers)->name ) ) ) {
	                        identPair = new std::pair<std::string, Identifier>();
	                        identPair->first = ( *( (*identifiers)->name ) );
	                        identPair->second = *(*identifiers);
	                        symbolTable.insert( *identPair );
	                    }
	                    else {
	                        error( "Ambiguous identifier definition" );
	                    }
	                }
	                identifiers++;
	            }
	        }
			it++;
		}
    }
}
